# -*- coding: utf-8 -*-
import csv #Libreria encargada de lectura de archivos csv
import datetime as d #Libreria para manejo de elementos temporales
import random as r #Libreria para manejo de elementos aleatorios

##
#Configuracion de constantes y variables...
tna= 0.2 #Tasa nominal anual de descuento
coef_va=-1 #Coeficiente de valoracion de carteras
max_mora=4 #Nivel de mora excesivo que genera rechazo de prestamo para cambio...
fecha_corte= d.date(2010,10,20) #Fecha de corte utilizada para formula de valor actual
dias=356 #Dias del año...
indice_ramificacion=50 #Cantidad de sucesores generados por expancion
iteraciones=100#Cantidad de reinicios para la corrida de un algoritmo
archivos_financiera= ('cartera_total.csv','flujo_total.csv') #Archivos completos de nuestra financiera
archivos_remplazar=('cartera_remplazar.csv','flujo_remplazar.csv')#Archivos de cartera a remplazar

##
#Funciones de apoyo del proyecto...
#Creamos funciones de ayuda y soporte
porcentaje= lambda: r.choice([0, 0.3, 0.3, 0.5, 0.5, 0.5, 0.75, 0.75, 0.75, 0.75, 0.9, 0.9, 0.9, 1])#Devuelve un porcentaje random
prom= lambda lista: sum(lista) / len(lista) #A partir de una lista no vacia, obtiene el promedio de la misma
cuota= lambda fstring,nstring: [fecha(fstring), numero(nstring)] #obtiene dos strings y devuelve una lista [date, float]
numero= lambda string :float(string.replace(",",".")) #Se encarga de cambiar un string "1,4" a float 1.4
fecha= lambda string: d.date(int(string.split("/")[2]),int(string.split("/")[1]),int(string.split("/")[0]))#Traduce string a objeto fecha

#Controlamos elementos en el ingreso de los archivos para evitar carga erronea...
son_numericos= lambda lista:all_true([es_numerico(item) for item in lista])#Esta funcion lee una lista y se encarga de controlar que sea numerica
es_numerico= lambda string: all_true([((ord(char)>47 and ord(char)<58) or ord(char)==44 or ord(char)==47) for char in string])#Devuelve True si todos los caracteres de una palabra son numeros, ',' o '/'
all_true= lambda boolean_list: sum(boolean_list)==len(boolean_list)#Recibe una lista de booleanos y si todos sus campos son True devuelve True, si alguno no lo es, devuelve False

def csv_to_dict(path,limiter=";"): #Funcion que levanta un csv y lo pasa a diccionario
    dic= {} #Crea el diccionario vacio
    lineas= csv.reader(open(path, 'rb'),delimiter=limiter) #Lee el archivo pasado como parametro
    for linea in [linea for linea in lineas if son_numericos(linea)]: #Recorre todas las lineas del archivo que no tengan letras adentro...
        if linea[0] in dic.keys(): dic[linea[0]].append(linea) #Si el diccionario, ya tiene esa clave, le agrega otro elemento al valor
        else: dic[linea[0]]= [linea,] #Si el archivo no tenia esa clave, crear el primer elemento...//Seran asi [[a],[b],[c],]
    return dic #Devuelve el diccionario ya cargado como resultado...

def cartera_to_csv(file_name,cartera,remplazar):#Funcion encargada de recibir una cartera y generar un archivo de excel
    w=csv.writer(open('%s.csv'%file_name, 'wb'), delimiter=';')#Crea el objeto "Escritor"
    w.writerow(['Cant_Prestamos:',len(cartera.prestamos),'Valor_Cartera:',cartera.valor_total(),'Diferencia:',cartera.valor_total()-remplazar.valor_total()])#Ponemos datos de cartera
    w.writerow(['Id_Prestamo','Id_Cliente','Mora_Actual','Mora_Maxima','Valor_Actual','Preferencia'])#Cabezales para lista de prestamos
    for prestamo in cartera.prestamos.values():#Recorremos todos los prestamos de la cartera
        w.writerow([prestamo.id_prestamo,prestamo.id_cliente,prestamo.mora[0],prestamo.mora[1],prestamo.valor_actual,prestamo.preferencia])#Pasamos datos como lista y genera una fila al csv.

##
#Metodos para el trabajo con listas
def lista_ponderada(lista): #Recibi una lista ordenada por calidad de mayor a menor y devuelve lista aumentada probabilisticamente
    long_lista=5#Cuantas se ampliara la lista extendida
    rep_item=0.07#Cuantas veces se repetira cada elemento segun tamaño de lista
    decrecimiento=0.05#Cuanto ira decreciendo la repeticion de elementos por lista
    res= [] #Creamos la lista que devolvera ya preparada probabilisticamente
    elementos= len(lista) * long_lista #Crea el tamaño que tendra la nueva lista
    for item in lista: #Recorremos todos los elementos que posee la lista original ordenada
        res+= [item for c in range(1 + int(elementos * rep_item))]#generamos mini listas de este elemento, dando mas peso a los primeros
        elementos-= elementos * decrecimiento #cada mini lista que agregamos, hace la proxima sea mas pequeña-> prox item menos posibilidades
    return res #Los mejores (Primeros) elementos tienen mas posibilidades de salir, por que estan mas veces repetidos...

get_item= lambda lista: r.choice(lista_ponderada(lista)) #Se le entrega la lista ordenada y devuelve un item, usando prioridades
comparar= [(lambda p1,p2: control(p1.valor_actual - p2.valor_actual)),(lambda p1,p2: control(p1.preferencia - p2.preferencia)),(lambda p1,p2: r.choice([-1,0,1]))]#[0]:ordena por valor de prestamo, [1]:Ordena por preferencia,[2]:Ordena al azar
control= lambda valor: int((int(valor<0)* -2) + 1)#Funcion que recibe un numero y se encarga de transformarlo en -1 0 1 dependiendo si es mayor o menor a 0
random_sort_list= lambda lista: sorted(lista, cmp=r.choice(comparar), reverse=r.choice([True,False])) #Funcion encargada de ordenar los elementos de la lista al azar, tomando de las otras los argumentos
sort_list= lambda lista, motivo, razon: sorted(lista,cmp=motivo,reverse=razon) #Ordena una lista segun un conjunto de parametros...
sort_ids= lambda lista, prioridad: [p.id_prestamo for p in sort_list(lista,prioridad[0],prioridad[1])] #Creamos una lista de ids de prestamos ordenandola por una prioridad...
